﻿#include <iostream>
#include <stdlib.h>
#include <cv.h>
#include <highgui.h>
#include <winsock2.h> 
#include <algorithm>
#include <string>
#include <zthread/ThreadedExecutor.h>
#include "Netprocess.h"

using std::string;
using std::cout;
using std::endl;
using namespace ZThread;

void initserver(SOCKET& server,int port);
void decodeYUV420SP(char* rgbBuf,const char * yuv420sp, int width, int height);
void YUV422TORGB24(char* rgbBuf,char * yuv422sp, int width, int height);
void myyuv422_rgb(const unsigned char * yuvdata,unsigned char * rgbdata,int width,int height);
bool imagebufferIsfull(void);
int indexadd(int _index);
int indexsub(int _index);
int buffercount(void);

////////////////////////////////
test svn
////////////////////////////////


//创建多线程类，一个类代表一个客户端
class clientT{
    public:
      clientT(SOCKET& _socket,string _ip):socket(_socket),ip(_ip){
          cout<<"ip为: "<<ip<<" 的客户端初始化"<<endl;
          
          videowindowname = new char[20];
          graywindowname  = new char[30];
          strcpy(videowindowname,"video ");
          strcat(videowindowname,ip.c_str());
          strcpy(graywindowname,"motion ");
          strcat(graywindowname,ip.c_str());
          
          
          //寻找运动物体,必须一些全局变量 
          MHI_DURATION = 1;
          MAX_TIME_DELTA = 0.5;
          MIN_TIME_DELTA = 0.05;
          backmat = 0;
          videomat = 0;
          foremat = 0;
          
          //创建一个线程接收图片到图片缓冲区 
          buffercapacity = 500;
          netprocess = new Netprocess(socket,buffercapacity);
          ThreadedExecutor executor; 
          executor.execute(netprocess);
          process();
      }       
      
      void process(){
          cvNamedWindow(videowindowname,0);
          cvNamedWindow(graywindowname,0);
          bool first = true;
          videoframe = NULL;
          while(true){
              //从缓冲区获取一张图片到videoframe; 
              cout<<"netprocess->buffercount():"<<netprocess->buffercount()<<endl;
              if( first&&(!netprocess->imagebufferIsempty()) ){
                 first = false;
                 
                 int width = netprocess->getwidth();
                 int height = netprocess->getheight();
                 cout<<"width:"<<width<<endl;
                 cout<<"height:"<<height<<endl;
                 videoframe = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,3);   
              }    
              //网络断开且缓冲为空，则退出循环 
              if( (!netprocess->connected()) && netprocess->imagebufferIsempty() )break;
              if(videoframe != NULL){        
                  char * testadd =  (char*)netprocess->getdataaddr();
                  
                  videoframe->imageData = testadd;
                  cvShowImage(videowindowname,videoframe);
                 
                  IplImage * motion = cvCreateImage(cvGetSize(videoframe),IPL_DEPTH_8U,3);
                  queryMotionFrame(videoframe,motion);
                  
                  cvShowImage(graywindowname,motion);
                  cvReleaseImage(&motion);
              }    
              if(cvWaitKey(100) == 'q')break;
              
          }//end while   
           
          cvReleaseImage(&videoframe);
          cvDestroyWindow(videowindowname);
          cvDestroyWindow(graywindowname);
          delete[] videowindowname;
          delete[] graywindowname;
          //如果执行到这里，这个客户完蛋了,销毁线程 
          closesocket(socket); 
      }
      ~clientT(){
           
           cout<<"ip为: "<<ip<<" 客户端销毁"<<endl;  
       }     
      
    private:
        
    //寻找运动物体,必须一些全局变量 
    double MHI_DURATION;
    double MAX_TIME_DELTA;
    double MIN_TIME_DELTA;
    CvMat * backmat;
    CvMat * videomat;
    CvMat * foremat;
    IplImage * motion_graybuf;
    IplImage * mhi;
    IplImage * orient;
    IplImage * mask;
    IplImage * segmask;
    void queryMotionFrame(IplImage * videoframe,IplImage * dstimage){
        CvMemStorage * storage = cvCreateMemStorage(0);
        if(!backmat){
            CvSize videosize = cvGetSize(videoframe);
            videomat = cvCreateMat(videoframe->height,videoframe->width,CV_32FC1);
            foremat = cvCreateMat(videoframe->height,videoframe->width,CV_32FC1);     
            backmat = cvCreateMat(videoframe->height,videoframe->width,CV_32FC1);  
            motion_graybuf = cvCreateImage(videosize,IPL_DEPTH_8U,1);
            
            mhi = cvCreateImage(videosize,IPL_DEPTH_32F,1);
            orient = cvCreateImage(videosize,IPL_DEPTH_32F,1);
            segmask = cvCreateImage(videosize,IPL_DEPTH_32F,1);
            mask = cvCreateImage(videosize,IPL_DEPTH_8U,1);
        }    
        
        cvCvtColor(videoframe,motion_graybuf,CV_BGR2GRAY);
        cvConvert(motion_graybuf,videomat);
        //当前帧减矩阵去背景矩阵得到前景矩阵 
        cvAbsDiff(videomat,backmat,foremat); 
        cvThreshold(foremat,motion_graybuf,60,255,CV_THRESH_BINARY);
        //存储背景矩阵 ,时间越大背景换得越快 
        cvRunningAvg(videomat,backmat,0.4,0);
        cvCvtColor(motion_graybuf,dstimage,CV_GRAY2BGR);    
        
        //新技术 -------------------------------------------------------------
        CvSeq * motionseq;
        double timestamp = (double)clock()/CLOCKS_PER_SEC; // get current time in seconds
        cvUpdateMotionHistory(motion_graybuf,mhi,timestamp,MHI_DURATION);
        cvCalcMotionGradient(mhi,mask,orient,MAX_TIME_DELTA,MIN_TIME_DELTA,3);
        
        //找出运动的区域 
        motionseq = cvSegmentMotion(mhi,segmask,storage,timestamp,60);
        float angle;
        angle = cvCalcGlobalOrientation(orient,mask,mhi,timestamp,MHI_DURATION);
        
        //在运动区域画标记 
        CvRect motionrect;
        CvPoint motioncenter;
        int radiu;
        for(int i = 0; i < motionseq->total; i++){
            motionrect = ( (CvConnectedComp*)cvGetSeqElem(motionseq,i) )->rect;
            radiu = sqrt((float)motionrect.width*motionrect.width +
                        +(float)motionrect.height*motionrect.height)/2.0;
            //筛选，区域太小的略去            
            if(radiu > 30){
               motioncenter.x = motionrect.x + motionrect.width/2;
               motioncenter.y = motionrect.y + motionrect.height/2;                    
               cvCircle(dstimage,motioncenter,30,CV_RGB(0,0,255),2,8,0); 
            }    
            
        }    
        
        cvReleaseMemStorage(&storage);
    }    
   
      
      Netprocess *netprocess;
      IplImage * videoframe;
      char *videowindowname;
      char *graywindowname;
      SOCKET socket; 
      string ip;  //客户对应ip 
      int buffercapacity;
      unsigned char * tempdata;
      /////////////////////////////////////
};     


int main()
{
  cout<<"依赖于opencv进行图像处理，需正确装好opencv"<<endl;  
  const int port = 54321;  
  SOCKET serversock;
  initserver(serversock,port);
  
  //先要有一些初始化，才能正确得到系统信息 
  char hostname[50];
  gethostname(hostname,50);
  cout<<"主机名:"<<hostname<<endl;
  struct hostent *host = gethostbyname(hostname);
  cout<<"服务器ip:";
  for(int i = 0;host->h_addr_list[i] != 0; i++){
      struct in_addr* ipaddr;
      memcpy(ipaddr, host->h_addr_list[i], sizeof(struct in_addr)); 
      string ip = inet_ntoa(*ipaddr);
      cout<<ip<<"  ";
  }    
  cout<<endl;  
  cout<<"绑定端口为: "<<port<<endl;
  
  string client_ip;
  
  
  //单线程的 
  while(true){
     
     struct sockaddr_in c_addr;  //客户地址   
     int addr_len =sizeof(c_addr);  
     cout<<"等待客户端....."<<endl;
     SOCKET clientsock = accept(serversock,(struct sockaddr*)&c_addr,&addr_len); //通过监听套接字创建连接套接字  
     client_ip = inet_ntoa(c_addr.sin_addr);
    
     clientT *client = new clientT(clientsock,client_ip);
     delete client;
  }    
  
  return 0;
}


void initserver(SOCKET& server,int port){
    cout<<"服务器初始化！....."<<endl;  
    //初始化winsock   
    WSADATA wsaD;  
    WSAStartup(MAKEWORD(1,1),&wsaD);  
    //创建监听套接字  
    server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);   
    // 绑定主机地址和监听套接字  
    struct sockaddr_in server_addr;   //主机地址   
    server_addr.sin_family      = AF_INET;  
    server_addr.sin_port        = htons(port); //指定端口  
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
    bind(server,(struct sockaddr *)&server_addr,sizeof(server_addr));  
    //启动监听  
    listen(server,5);  
    
}    







